<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>改变this的指向</title>
    <!-- 
        JavaScript 为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部 this 的指向问题，
        常用的有 call()、apply()、bind()三种方法。
        1. call 方法 `
        call() 方法调用一个对象。简单理解为调用函数的方式，但是它可以改变函数的 
        this 指向。 
        fun.call(thisArg, arg1, arg2, ...) 
        thisArg：在 fun 函数运行时指定的 this 值；
        arg1，arg2：传递的其他参数；
        返回值就是函数的返回值，因为它就是调用函；
        因此当我们想改变 this 指向，同时想调用这个函数的时候，可以使用 call，比如继承。

        2. apply 方法
        apply() 方法调用一个函数。简单理解为调用函数的方式，它也可以改变函数的 this 指向。
        fun.apply(thisArg, [argsArray])
        thisArg：在 fun 函数运行时指定的 this 值；
        argsArray：传递的值，必须包含在数组里面；
        返回值就是函数的返回值，因为它就是调用函数；
        因此 apply 主要跟数组有关系，比如使用 Math.max() 求数组的最大值。

        3. bind 方法
        bind() 方法不会调用函数。但是能改变函数内部 this 指向。
        fun.bind(thisArg, arg1, arg2, ...)
        thisArg：在 fun 函数运行时指定的 this 值；
        arg1，arg2：传递的其他参数；
        返回由指定的 this 值和初始化参数改造的原函数拷贝；
        因此当我们只是想改变 this 指向，并且不想调用这个函数的时候，可以使用 bind。

     -->
</head>
<body>
    <button>1</button>
    <button>2</button>
    <button>3</button>
</body>
<script>
    // 改变函数内this指向  js提供了三种方法  call()  apply()  bind()
    console.log('**************call()*****************');
    var o = {
        name:'andy'
    }
    function fn(a,b) {
        console.log(this);
        console.log(a+b);
    }
    fn.call(o,1,2)
    // call 第一个可以调用函数 第二个可以改变函数内的this 指向
    // call 的主要作用可以实现继承
    function Father(uname,age,sex) {
        this.uname = uname
        this.age = age
        this.sex = sex
    }
    function Son(uname,age,sex) {
        Father.call(this,uname,age,sex)
    }
    var son = new Son('smx',18,'女')
    console.log(son);
    console.log('**************apply()*****************');
    var o1 = {
        name: 'shuangmuxi'
    }
    function fn1(arr) {
        console.log(this);
        console.log(arr);
    }
    fn1.apply(o1,['pink'])
    // 1. 也是调用函数 第二个可以改变函数内部的this指向
    // 2. 但是他的参数必须是数组(伪数组)
    // 3. apply 的主要应用 比如说我们可以利用 apply 借助于数学内置对象求数组最大值 
    // Math.max();
    var arr1 = [12,23,34,24,14,25,35,63,76,33]
    var max = Math.max.apply(Math,arr1)
    var min = Math.min.apply(Math,arr1)
    console.log(max,min);
    console.log('**************bind()*****************');
    var o2 = {
        name:'caomengxing'
    }
    function fn2(a,b) {
        console.log(this);
        console.log(a + b);
    }
    var f = fn2.bind(o2,1,2)
    f()
    // 1. 不会调用原来的函数   可以改变原来函数内部的this 指向
        // 2. 返回的是原函数改变this之后产生的新函数
        // 3. 如果有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向此时用bind
        // 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒钟之后开启这个按钮
        // var btn1 = document.querySelector('button');
        // btn1.onclick = function() {
        //     this.disabled = true; // 这个this 指向的是 btn 这个按钮
        //     // var that = this;
        //     setTimeout(function() {
        //         // that.disabled = false; // 定时器函数里面的this 指向的是window
        //         this.disabled = false; // 此时定时器函数里面的this 指向的是btn
        //     }.bind(this), 3000); // 这个this 指向的是btn 这个对象
        // }
    var btns = document.querySelectorAll('button')
    for(var i=0;i<btns.length;i++){
        btns[i].onclick = function() {
            this.disabled = true
            setTimeout(function(){
                this.disabled = false
            }.bind(this),2000)
        }
    }

</script>
<!-- 
    call apply bind 总结
相同点：

 都可以改变函数内部的 this 指向。

区别点：
1. call 和 apply 会调用函数, 并且改变函数内部 this 指向；
2. call 和 apply 传递的参数不一样, call 传递参数 aru1, aru2..形式 apply 必须数组形式[arg]；
3. bind 不会调用函数, 可以改变函数内部this指向。

主要应用场景：
1. call 经常做继承；
2. apply 经常跟数组有关系. 比如借助于数学对象实现数组最大值最小值；
3. bind 不调用函数,但是还想改变this指向. 比如改变定时器内部的 this 指向。
 -->
</html>